package com.lewei.open.reject.repeated.submit.config;

import com.lewei.open.distributed.lock.core.DistributedLock;
import com.lewei.open.reject.repeated.submit.exception.DistributedLockException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

import java.lang.reflect.Constructor;
import java.util.Objects;

import static com.lewei.open.reject.repeated.submit.constants.DistributedLockConstants.REDIS_DISTRIBUTED_LOCK;
import static com.lewei.open.reject.repeated.submit.constants.DistributedLockConstants.ZOOKEEPER_DISTRIBUTED_LOCK;

/**
 * @author yins
 * @date 2021年11月08日 20:45
 * @since 1.0.0
 */
@Configuration
public class DistributedLockConfiguration {

    private final Logger log = LoggerFactory.getLogger(getClass());

    @Bean
    @ConditionalOnMissingBean(DistributedLock.class)
    @ConditionalOnClass(name = REDIS_DISTRIBUTED_LOCK)
    public DistributedLock redisDistributedLock(@Autowired RedisTemplate redisTemplate) {
        try {
            Class clazz = Class.forName(REDIS_DISTRIBUTED_LOCK);
            Constructor constructor = clazz.getConstructor(RedisTemplate.class);
            Object newInstance = constructor.newInstance(redisTemplate);
            DistributedLock instance = (DistributedLock) newInstance;
            log.info("Successfully initialized the distributed lock based on Redis");
            return instance;
        } catch (Exception e) {
            throw new DistributedLockException(e);
        }

    }


    @Bean
    @ConditionalOnMissingBean(DistributedLock.class)
    @ConditionalOnClass(name = ZOOKEEPER_DISTRIBUTED_LOCK)
    public DistributedLock zookeeperDistributedLock() {
        DistributedLock instance = getInstanceByClassName(ZOOKEEPER_DISTRIBUTED_LOCK);
        log.info("Successfully initialized the distributed lock based on Zookeeper");
        return instance;
    }


    private DistributedLock getInstanceByClassName(String className) {
        Objects.requireNonNull(className, "The class name must not null");
        try {
            Class clazz = Class.forName(className);
            Object instance = clazz.newInstance();
            return (DistributedLock) instance;
        } catch (Exception e) {
            throw new DistributedLockException(e);
        }
    }

}
